#!/usr/bin/env python
#!conding:utf-8
"""
author:Johnson
date: 2017/5/16 15:35
version: v1.0
description:
    用户信息和权限信息
"""
from datetime import datetime
from flask_login.mixins import UserMixin,AnonymousUserMixin
from itsdangerous import TimedJSONWebSignatureSerializer
from werkzeug.security import generate_password_hash, check_password_hash
from blog import db, login_manager, model, app
from blog.model import get_all


class User(UserMixin, db.Model):
    """
        引入flask_login之后需要基础UserMixin
        is_authenticated() 当用户通过验证时，也即提供有效证明时返回 True 。（只有通过验证的用户 会满足 login_required 的条件。）
        is_active()如果这是一个活动用户且通过验证，账户也已激活，未被停用，也不符合任何你 的应用拒绝一个账号的条件，返回 True 。不活动的账号可能不会登入（当然， 是在没被强制的情况下）。
        is_anonymous()如果是一个匿名用户，返回 True 。（真实用户应返回 False 。）
        get_id()返回一个能唯一识别用户的，并能用于从 user_loader 回调中 加载用户的 unicode 。注意着 必须 是一个 unicode ——如果 ID 原本是 一个 int 或其它类型，你需要把它转换为 unicode 。
    """
    __tablename__ = 't_user'

    id = db.Column(db.Integer,primary_key=True)
    password_hash = db.Column(db.String(128),nullable=False)
    username = db.Column(db.String(64))
    email = db.Column(db.String(64),unique=True)
    create_time = db.Column(db.DateTime,default=datetime.utcnow())
    confirmed = db.Column(db.Boolean,default=False)   # 默认未经过邮件验证
    last_seen = db.Column(db.DateTime,default=datetime.utcnow())    #上次登录时间

    def __init__(self,**kwargs):
        super(User,self).__init__(**kwargs)

    @property
    def password(self):
        raise AttributeError('password is not readable attribute!')
    @password.setter
    def password(self,password):
        ## 生成密码
        self.password_hash = generate_password_hash(password=password)


    def verify_password(self,password):
        ## 根据传入的密码判断是否和系统密码一致
        return check_password_hash(self.password_hash,password)

    def generate_confirmation_token(self,expire = 3600):
        ## 生成注册验证的token
        s = TimedJSONWebSignatureSerializer(secret_key=app.config['SECRET_KEY'],expires_in=expire)
        return s.dumps({'confirm':self.id})
    def confirm(self,token):
        s = TimedJSONWebSignatureSerializer(secret_key=app.config['SECRET_KEY'])
        try:
            data = s.loads(token)
        except:
            return False
        if data.get('confirm') != self.id:
            return False
        self.confirmed = True
        db.session.add(self)
        return True

    @classmethod
    def get_by_id(id):
        sql = "select * from :table where id = :id"
        param = {
            'table':User.__tablename__ ,
            'id':id
        }
        return model.get_by_id(sql,param)

    def get_by_mail(self):
        return User.query.filter_by(email= self.email).first()

    def get_by_username(self):
        return User.query.filter_by(username = self.username).first()
    ## 每次登录，修改上次登录时间
    def ping(self):
        self.last_seen = datetime.utcnow()
        db.session.add(self)
    ## update
    def update_by_type(self,param):
        """
            此方法中param必须存在一个参数id:xx
        :param param: json类型参数
        :param idValue 主键id的值
        :return:
        """
        sql = "update "+ User.__tablename__ +" set "
        for key in param.keys():
            sql = sql + key + "= :" + key+","
        sql = sql[:len(sql)-1]
        sql = sql+ " where id = :id"
        param['id'] = self.id
        model.execute(sql,param)

    ## 判断是否具有某个权限
    def can(self,permission):
        sql = "SELECT t2.permission_id FROM t_user_role t1 JOIN t_role_permission t2 ON t2.role_id = t1.role_id  WHERE t1.id = :id"
        param = {"id":self.id}
        permissions = get_all(sql,param)
        for item in permissions:
            if item[0] == permission:
                return True
        return False
    ## 判断是否具有管理权限
    def is_administrator(self):
        return self.can()

## 匿名用户
class AnonymousUser(AnonymousUserMixin):
    ## 判断是否具有某个权限
    def can(self,permissions):
        return False
    ## 判断是否具有管理权限
    def is_administrator(self):
        return False


@login_manager.user_loader
def load_user(user_id):
    """
        使用flask_login必须实现 @login_manager.user_loader这个修饰器的函数，内容为根据ID获取用户信息
    """
    return User.query.get(int(user_id))


class Role(db.Model):
    """
    角色表
    """
    __tablename__ = 't_role'
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(64))

class UserRole(db.Model):
    """
    用户角色对应表
    """
    __tablename__ = 't_user_role'
    id = db.Column(db.Integer,primary_key=True)
    user_id = db.Column(db.Integer)
    role_id = db.Column(db.Integer)

class Permission(db.Model):
    """
    权限表
    """
    __tablename__ = 't_permission'
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(64)) #权限描述

class RolePermission(db.Model):
    """
    角色权限对应表
    """
    __tablename__ = 't_role_permission'
    id = db.Column(db.Integer,primary_key=True)
    role_id = db.Column(db.Integer)
    permission_id = db.Column(db.Integer)




